﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;

namespace OpenPhotoAlbum.Controls
{
    public class CaptchaPainter
    {
        #region Singleton

        private static readonly CaptchaPainter instance = new CaptchaPainter();

        static CaptchaPainter() { }

        public static CaptchaPainter Instance
        {
            get { return instance; }
        }

        private CaptchaPainter()
        {
        }

        #endregion

        private const int WIDTH = 85;
        private const int HEIGHT = 35;
        private const string FONT_FAMILY_NAME = "Verdana";
        private const int FONT_SIZE = 20;

        private readonly Brush _bgBrush = new HatchBrush(HatchStyle.SmallConfetti, Color.Silver, Color.White);
        private readonly Brush _numberBrush = new HatchBrush(HatchStyle.SmallConfetti, Color.White, Color.DarkGray);
        private readonly Brush _noiseBrush = new SolidBrush(Color.FromArgb(32, Color.Black));
        private readonly Random _rn = new Random();

        public byte[] Paint(int number, ImageFormat format)
        {
            Bitmap canvas = new Bitmap(WIDTH, HEIGHT);
            Graphics gr = Graphics.FromImage(canvas);
            
            // Fill the background.
            gr.FillRectangle(_bgBrush, 0, 0, WIDTH, HEIGHT);

            // Draw the number.
            gr.DrawString(
                number.ToString("D4", CultureInfo.InvariantCulture),
                new Font(FONT_FAMILY_NAME, FONT_SIZE, FontStyle.Bold),
                _numberBrush, 0, 0);

            // Draw the noise.
            int x = _rn.Next(-WIDTH / 2, WIDTH / 2);
            int y = _rn.Next(-HEIGHT / 2, HEIGHT / 2);
            int width = _rn.Next(WIDTH / 2, WIDTH);
            int height = _rn.Next(HEIGHT / 2, HEIGHT);
            gr.FillEllipse(_noiseBrush, x, y, width, height);

            // Save to byte array.
            MemoryStream ms = new MemoryStream();
            canvas.Save(ms, format);
            byte[] result = ms.ToArray();
            
            ms.Close();
            gr.Dispose();
            canvas.Dispose();

            return result;
        }
    }
}
